/*
Copyright 2007 Stuart Maier.
This file is part of The Neural Network Compiler.

The Neural Network Compiler is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

The Neural Network Compiler is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with The Neural Network Compiler.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdio.h>
#include <string.h>

int token_converter(char token[])
{
	/* Returns the token code of the token. */
	
	/* Check if token is "createneuron". */
	if(token[0] == 'c' && token[1] == 'r' && token[2] == 'e' &&
	   token[3] == 'a' && token[4] == 't' && token[5] == 'e' &&
	   token[6] == 'n' && token[7] == 'e' && token[8] == 'u' &&
	   token[9] == 'r' && token[10] == 'o' && token[11] == 'n')
	{
		return 1;
	}
	
	/* Check if token is "deleteneuron". */
	if(token[0] == 'd' && token[1] == 'e' && token[2] == 'l' &&
	   token[3] == 'e' && token[4] == 't' && token[5] == 'e' &&
	   token[6] == 'n' && token[7] == 'e' && token[8] == 'u' &&
	   token[9] == 'r' && token[10] == 'o' && token[11] == 'n')
	{
		return 2;
	}
	
	/* Invalid token. */
	else
	{
		return 0;
	}
}

int lex(FILE *input_file)
{
	printf("Running the lexical analyzer.\n");
	
	/* Char to be processed. */
	int current_char;
	current_char = fgetc(input_file);
	
	/* Token to be processed. */
	char current_token[1024];
	int token_clear;
	for(token_clear = 0; token_clear < 1024; token_clear++)
	{
		current_token[token_clear] = 0;
	}
	
	/* Length of current token. */
	int counter;
	counter = 0;
	
	/* File we output tokens to. */
	FILE *token_file;
	token_file = fopen("compile.token", "wb");
	
	/* File we output symbols to. */
	FILE *symbol_file;
	symbol_file = fopen("compile.symbol", "w");
	int symbol_count;
	symbol_count = 0;
	
	/* Symbol table. */
	char symbol_table[256][1024];
	int symbol_count_one;
	int symbol_count_two;
	for(symbol_count_one = 0; symbol_count_one < 256; symbol_count_one++)
	{
		for(symbol_count_two = 0; symbol_count_two < 1024;
		    symbol_count_two++)
		{
			symbol_table[symbol_count_one][symbol_count_two] = 0;
		}
	}
	int symbol_exists;
	symbol_exists = -1;
	
	/* Flag for whether we are in a statement. */
	int inside_statement;
	inside_statement = 0;
	
	/* Current statement. */
	int current_statement;
	
	/* Parse the whole file. */
	while(current_char != EOF)
	{
		/* Remove leading whitespace. */
		if(counter == 0)
		{
			/* Check for semicolon, write it. */
			if(current_char == ';')
			{
				printf(";\n");
				fputc(0, token_file);
				inside_statement = 0;
			}
			/* Spaces, tabs, and newlines. */
			else if(current_char != 9 && current_char != 10 &&
				current_char != 32)
			{
				current_token[counter] = current_char;
				counter++;
			}
			else
			{
			}
		}
		else
		{
			/* Finish token after a whitespace or semicolon. */
			if(current_char == 9 || current_char == 10 ||
			   current_char == 32 || current_char == ';')
			{
				printf("%s\n", current_token);
				
				/* Write token(s) to file. */
				if(inside_statement == 0 &&
				   current_token[0] != ';')
				{
					/* Convert token to int symbol. */
					int token_symbol;
					token_symbol =
					token_converter(current_token);
					
					/* Check for tokenization failure. */
					if(token_symbol == 0)
					{
						printf("Invalid token.\n");
						return 1;
					}
					
					/* Write the token symbol. */
					fputc(token_symbol, token_file);
					counter = 0;
					inside_statement = 1;
				}
				else if(current_token[0] != ';')
				{
					/* Check if symbol exists. */
					for(symbol_count_one = 0;
					    symbol_count_one < 256;
					    symbol_count_one++)
					{
						if(strcmp(current_token,
							  symbol_table[
							  symbol_count_one])
						   == 0)
						{
							symbol_exists =
							symbol_count_one;
						}
					}
					
					/* Write old symbol to file. */
					if(symbol_exists >= 0)
					{
						fputc(255, token_file);
						fputc(symbol_exists,
						      token_file);
						counter = 0;
						symbol_exists = -1;
					}
					else
					{
						/* Write new symbol. */
						fputc(255, token_file);
						fputc(symbol_count,
						      token_file);
						strcpy(symbol_table[
						       symbol_count],
						       current_token);
						fprintf(symbol_file, "%s\n",
							current_token);
						symbol_count++;
						counter = 0;
					}
				}
				
				/* Check for semicolon, write it. */
				if(current_char == ';')
				{
					printf(";\n");
					fputc(0, token_file);
					inside_statement = 0;
				}
				
				/* Clear token array. */
				for(token_clear = 0; token_clear < 1024;
				    token_clear++)
				{
					current_token[token_clear] = 0;
				}
			}
			else
			{
				/* Add current char to array. */
				current_token[counter] = current_char;
				counter++;
			}
		}
		/* If counter is 1024, token is too long. */
		if(counter == 1024)
		{
			printf("Invalid token.\n");
			return 1;
		}
		
		/* Get next char. */
		current_char = fgetc(input_file);
	}
}

